#pragma once
#include <iostream>
#include <string>
#include "Commn.hpp"
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
#include "Log.hpp"
#include <ctime>
#include <vector>
#include <cstring>
using namespace LogModule;

const std::string Sep = "\r\n";
const std::string BankLine = Sep;
const std::string LineSep = " ";
const std::string HeaderSep = ": ";
const std::string HomePage = "wwwroot";
const std::string FirstPage = "index.html";
const std::string _404Page = "wwwroot/404.html";

class Request
{
public:
    Request()
    {
    }
    ~Request() {}
    void ParseHeader(std::string &in_str)
    {
        std::string line;
        while (true)
        {
            std::string k, v;
            bool r = ParseOneLine(&line, in_str, Sep);
            if (r && !line.empty())
            {
                // 正常报文
                SplitHeader(line, &k, &v, HeaderSep);
                _headerkv.insert(std::make_pair(k, v));
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blankLine = BankLine;
                break;
            }
            else // 没有空行
            {
                return;
            }
        }
    }
    void Deserialize(std::string &in_str)
    {
        _execv = false;
        if (ParseOneLine(&_reqLine, in_str, Sep))
        {
            ParseReqLine();
            ParseHeader(in_str);
        }
        _body = in_str;

        if (_method == "GET")
        {
            auto pos = _url.find("?");
            if (pos != std::string::npos)
            {
                _path = _url.substr(0, pos); // /login
                _args = _url.substr(pos + 1); // username=xxx&xxx
                _execv = true;
            }
        }
        else if (_method == "POST")
        {
            _path = _url; // /login
            _execv = true;
            _args = _body; //username=xxx&xxx
        }


    }
	void Parse()
	{
		std::string cookies = "Cookie: ";
		for (auto& line : _req_header)
		{
			// std::cout << "line: " << line << std::endl;
			if (strncmp(line.c_str(),cookies.c_str(),cookies.size()) == 0) 
			{
				// std::cout << "找到了" << line << std::endl;
				_cookies.push_back(line.substr(cookies.size()));
				break;
			}
		}
		std::string preffix = "sessionid=";
		for (auto& line : _cookies)
		{
			if (line.find(preffix) != std::string::npos) 
			{
				_sessionid = line.substr(preffix.size());
				// std::cout << "sessionid: " << _sessionid << std::endl;
				break;
			}
		}
		Test();
	}
    // const Request* req
    std::string Path() const { return _path; } // Request* const
    std::string Args() const { return _args; }
    bool HasArgs() { return _execv; }

    void SplitHeader(std::string &str, std::string *k, std::string *v, const std::string &sep)
    {
        auto pos = str.find(sep);
        if (pos == std::string::npos)
            return;
        *k = str.substr(0, pos);
        *v = str.substr(pos + sep.size());
    }
    void Test()
    {
        for (auto &line : _cookies)
        {
		std::cout << line << std::endl;
        }
    }
    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_url: " << _url << std::endl;
        std::cout << "_edition: " << _edition << std::endl;

        std::cout << _reqLine;
        for (auto &x : _req_header)
            std::cout << x;

        std::cout << _blankLine;
        std::cout << "_body: " << _body << std::endl;
    }
    std::string GetContent(const std::string &url) const
    {
        // //暂时的版本
        // std::ifstream in(_url.c_str());
        // if (!in.is_open()) return std::string(); //文件不存在的话直接返回空
        // std::string line;
        // std::string content;
        // while(std::getline(in,line))
        // {
        //     content += line;
        // }
        // return content;
        std::string content;
        std::ifstream in(url.c_str(), std::ios::binary);
        if (!in.is_open())
            return std::string(); // 文件不存在的话直接返回空
        in.seekg(0, in.end);
        int fullsize = in.tellg();
        content.resize(fullsize);
        in.seekg(0, in.beg);
        in.read((char *)content.c_str(), fullsize);
        in.close();
        return content;
    }
    std::string Url() { return _url; }
    void SetUrl(const std::string &url) { _url = url; }

    std::string GetSessionId()
    {
	    return _sessionid;
    }
private:
    inline void ParseReqLine()
    {
        std::stringstream ss(_reqLine);
        ss >> _method >> _url >> _edition;
        // _url = HomePage + _url;
        // LOG(LogLevel::DEBUG) << "url: " << _url;
    }
    std::string _sessionid;
    std::string _reqLine;
    std::vector<std::string> _req_header;
    std::string _blankLine;
    std::string _body;
    std::unordered_map<std::string, std::string> _headerkv;
	std::vector<std::string> _cookies;
    std::string _method;
    std::string _url;
    std::string _edition;
    bool _execv = false;
    std::string _path;
    std::string _args;
};

class Response
{
public:
    Response()
        : _version("HTTP/1.0")
    {
    }
    ~Response() {}

    void Build(Request &req)
    {

        std::string url = HomePage + req.Url();
        LOG(LogLevel::DEBUG) << "当前的url: " << url;
        if (url.back() == '/')
            url += FirstPage; // 访问目录的时候，直接定位默认首页
        _body = req.GetContent(url);
        if (_body.empty()) // 文件不存在
        {
            _status = 404;
            // req.SetUrl(_404Page);
            // url = _404Page;
            _body = req.GetContent(_404Page);
            // LOG(LogLevel::DEBUG) << "报错修正后的url: " << req.Url();
        }
        else
        {
            _status = 200;
        }
        LOG(LogLevel::INFO) << "之后url: " << url;

        _status_desc = Status2Desc();

        std::string mime_type;
        if (!_body.empty()) //_body不为空
        {
            SetHeader("Content-Length", std::to_string(_body.size()));
        }
        mime_type = suf2type(sufixinfo(req.Url()));
        SetHeader("Content-Type", mime_type);
    }
    std::string GetMonthName(int month)
    {
        std::vector<std::string> months = {"Jan", "Feb", "Mar",
                                           "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return months[month];
    }

    std::string GetWeekDayName(int day)
    {
        std::vector<std::string> weekdays = {"Sun", "Mon", "Tue",
                                             "Wed", "Thu", "Fri", "Sat"};
        return weekdays[day];
    }
    std::string GetExpiresTime(int t)
    {
        time_t time_out = time(nullptr) + t;
        struct tm *tm = gmtime(&time_out); // 这里要用gmtime,不能使用localtime,localtime带有时区
        char inbuffer[1024];
        snprintf(inbuffer, sizeof(inbuffer), "%s, %02d %s %04d %02d:%02d:%02d",
                 GetWeekDayName(tm->tm_wday).c_str(),
                 tm->tm_mday,
                 GetMonthName(tm->tm_mon).c_str(),
                 tm->tm_year + 1900,
                 tm->tm_hour,
                 tm->tm_min,
                 tm->tm_sec);
        return inbuffer;
    }
    void SetBody(std::string &body)
    {
        _body = body;
    }
    void SetCode(int code)
    {
        _status = code;
        _status_desc = Status2Desc();
    }
    void SetHeader(const std::string &k, const std::string &v)
    {
        _headerkv.insert(std::make_pair(k, v));
    }
    void AddHeader(const std::string &s)
    {
        _req_header.push_back(s + Sep);
    }
    void Serialize(std::string *out_str)
    {
        _reqLine = _version + LineSep + std::to_string(_status) + LineSep + _status_desc + Sep;
        *out_str = _reqLine;
        
        for (auto &line : _headerkv)
        {
            std::string str;
            GetReqHeader(&str, line.first, line.second, HeaderSep);
            _req_header.push_back(str + Sep); // 添加\r\n
        }

        for (auto &line : _req_header)
        {
            *out_str += line;
        }
        _blankLine = BankLine;
        *out_str += _blankLine;
        *out_str += _body;
    }
    void GetReqHeader(std::string *out, const std::string &k, const std::string &v, const std::string &sep)
    {
        *out = k + sep + v;
    }
    std::string sufixinfo(const std::string &url)
    {
        auto pos = url.rfind(".");
        if (pos == std::string::npos)
            return std::string();
        return url.substr(pos);
    }
    std::string suf2type(const std::string &s)
    {
        if (s == ".jpj")
            return "application/x-jpg";
        else if (s == ".html")
            return "text/html";
        else
            return "text/html";
    }

private:
    std::string Status2Desc()
    {
        switch (_status)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return "OK";
        }
        return "OK";
    }

private:
    std::string _reqLine;
    std::vector<std::string> _req_header;
    std::string _blankLine;
    std::string _body;

    std::unordered_map<std::string, std::string> _headerkv;
    std::string _version;
    int _status;
    std::string _status_desc;
};
